﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace Netfraction.Network.Protocol.BASE
{
    [ProtocolFeature(Name="BASE")]
    public class ProtocolFeatureBASE : ProtocolFeature, IProtocolFileListFeature
    {
        public struct FeatureActions
        {
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionSTA = "STA";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionSUP = "SUP";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionSID = "SID";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionINF = "INF";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionMSG = "MSG";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionSCH = "SCH";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionRES = "RES";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionCTM = "CTM";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionRCM = "RCM";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionGPA = "GPA";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionPAS = "PAS";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionQUI = "QUI";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionGET = "GET";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionGFI = "GFI";
            [ProtocolFeatureAction(ActionType = FeatureActionType.Message)]
            public const string ActionSND = "SND";
        }

        private const string FILE_LIST_NAME = "files.xml";

        public ProtocolFeatureBASE()
        {
            this.SupportedActions.AddRange(base.GetFeatureActions(new FeatureActions()));
            
            // Register Handlers
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionSUP, FeatureActionType.Message), new Handler.HandlerSUP());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionINF, FeatureActionType.Message), new Handler.HandlerINF());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionMSG, FeatureActionType.Message), new Handler.HandlerMSG());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionCTM, FeatureActionType.Message), new Handler.HandlerCTM());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionRCM, FeatureActionType.Message), new Handler.HandlerRCM());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionRES, FeatureActionType.Message), new Handler.HandlerRES());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionSCH, FeatureActionType.Message), new Handler.HandlerSCH());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionGET, FeatureActionType.Message), new Handler.HandlerGET());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionGPA, FeatureActionType.Message), new Handler.HandlerGPA());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionQUI, FeatureActionType.Message), new Handler.HandlerQUI());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionSID, FeatureActionType.Message), new Handler.HandlerSID());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionSND, FeatureActionType.Message), new Handler.HandlerSND());
            this.ProtocolMessageHandlers.Add(new ProtocolFeatureAction(FeatureActions.ActionSTA, FeatureActionType.Message), new Handler.HandlerSTA());

            ShareManager.ShareManager sManager = ShareManager.ShareManager.GetInstance();
            lock (sManager)
            {
                sManager.RegisterFileListName(FILE_LIST_NAME, this);
            }
        }

        /// <summary>
        /// Overrides the ProtocolFeature.HandleConnect method
        /// </summary>        
        public override bool HandleConnect(RemoteMachine.Node node)
        {
            // Update Connection State
            node.Connection.State = RemoteMachine.ConnectionState.Protocol;

            // Get Client
            LocalMachine.Client client = LocalMachine.Client.GetInstance();

            ProtocolMessageFactory factory = new Factory.FactorySUP();

            Dictionary<int, object> parameters = new Dictionary<int, object>();
            parameters.Add((int)Factory.FactorySUP.ParameterEnum.AddFeature, new List<string>(client.Features.Keys));

            ProtocolMessage message = null;
            if (node is RemoteMachine.Hub)
            {
                message = factory.Create(ProtocolMessage.MessageTypeEnum.Hub, parameters);
            }
            else if (node is RemoteMachine.Peer)
            {
                message = factory.Create(ProtocolMessage.MessageTypeEnum.Client, parameters);
            }

            if (message != null)
            {
                node.Connection.Send(message.ToString());
            }

            return true;
        }

        /// <summary>
        /// Overrides the ProtocolFeature.HandleDisconnect method
        /// </summary>        
        public override bool HandleDisconnect(RemoteMachine.Node node)
        {
            return true;
        }

        #region IProtocolFileListFeature Members

        MemoryStream IProtocolFileListFeature.WriteToFileList(MemoryStream stream)
        {
            // this should call the share manager to retrieve a Directory tree, then generate an XML file in memory
            string fListPath = @"E:\ADC\Netfraction\Test Data\Emptyfiles.xml";
            using (FileStream fs = new FileStream(fListPath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                WriteToStream(fs, stream);
            }

            return stream;  // when returning in-memory built stream this will probably be new MemoryStream(xDoc.ToStream()) or something
        }
        
        MemoryStream IProtocolFileListFeature.ReadFromFileList(MemoryStream stream)
        {
            Console.WriteLine("BASE list reader");
            return stream;
        }

        private static void WriteToStream(Stream inStream, Stream outStream)
        {
            int size;
            byte[] buffer = new byte[4096];
            do
            {
                size = inStream.Read(buffer, 0, buffer.Length);
                if (size > 0)
                {
                    outStream.Write(buffer, 0, size);
                }
            }
            while (size > 0);
        }

        #endregion
    }
}
